#! /bin/bash

# Copyright (c) 2014 by Albert Gräf <aggraef@gmail.com>. Distributed under
# the LGPL, please see the accompanying COPYING files for details.

#set -x

# compiler flags (you can change these by setting them in the environment)
CXX="${CXX:-g++}"
CFLAGS="${CFLAGS:--O3}"
CPPFLAGS="${CPPFLAGS:-}"
LIBS="${LIBS:-}"

# These should be detected properly at build time, but you can also set them
# to alternative locations using the SDK and SDKSRC environment variables.
# Set this to the location where you keep your VST SDK files.
[ -z $SDK ] && SDK=@SDK@
# SDKSRC should point to the SDK source files (vstplugmain.cpp et al).
# Usually these are either directly under $SDK or in the
# public.sdk/source/vst2.x subdirectory.
[ -z $SDKSRC ] && SDKSRC=@SDKSRC@

if [ "$SDK" = "$SDKSRC" ]; then
  INCLUDES="-I$SDK"
else
  INCLUDES="-I$SDK -I$SDKSRC"
fi

prog=`basename "$0"`

usage() {
  echo "USAGE: $prog [-h] [-u] [-o output-filename] script-name ..." >&2
  echo "-h, --help:      print this message and exit" >&2
  echo "-o, --output:    specify the output filename" >&2
  echo "-u, --universal: create a universal binary (Mac OS X only)" >&2
}

# Parse options using getopt(1).
args=`getopt  -o ho:u -l help,output:,universal -n "$prog" -- "$@"`
if [ $? != 0 ] ; then exit 1 ; fi
eval set -- "$args"

while true; do
  case "$1" in
    -h|--help) usage; exit 1 ;;
    -o|--output) output="$2"; shift 2 ;;
    -u|--universal) universal="yes"; shift ;;
    --) shift; break ;;
  esac
done

if [ -z "$1" ]; then
  echo "$prog: no script name specified (try '$prog -h' for help)" >&2
  exit 1
fi

filename="$1"
shift

plugin=`basename "$filename" .pure`
dirname=`dirname "$filename"`
# This symbol ought to be a valid C identifier, so we mangle the plugin name
# if necessary.
name=`echo -n "$plugin" | tr -c [:alnum:] _`
loader="__${name}_main__"
tmpname="__${plugin}_main__.pure"
logname="$dirname/$plugin.log"
objname="$dirname/$plugin.o"

# Platform-specific setup.
DLL=`pkg-config pure --variable DLL`
PIC=`pkg-config pure --variable PIC`
shared=`pkg-config pure --variable shared`
libdir=`pkg-config pure --variable libdir`

MOD_CFLAGS="$PIC `pkg-config pure --cflags` $CFLAGS $CPPFLAGS"
MOD_LDFLAGS="`pkg-config pure --libs` $LDFLAGS"

if [[ $(uname) == Darwin ]]; then
  # Mac-specific setup (output is a MachO bundle)
  shared=-bundle
  output="${output:-$dirname/$plugin.vst}"
  soname="$output/Contents/MacOS/$plugin"
  if [ "$universal" = "yes" ]; then
    # Options to create universal binaries on the Mac.
    cxxarch="i386 x86_64"
    ARCH=`printf -- "-arch %s -arch %s" $cxxarch`
  fi
else
  output="${output:-$dirname/$plugin$DLL}"
  soname="$output"
fi

# Extra sources with VST-specific code needed to build the plugins.
main=$SDKSRC/vstplugmain.cpp
afx=$SDKSRC/audioeffect.cpp
afxx=$SDKSRC/audioeffectx.cpp
extrasources="$main $afx $afxx"

# NOTE: The following requires that the cwd is writeable, since we create some
# files there.

# This makes sure that the requisite functions and variables aren't
# accidentally stripped from the binary during batch compilation.
rm -f $tmpname
for x in manifest plugin Name Author Description Version; do
  echo "#! --required $x" >> $tmpname
done
# Invoke Pure to compile the plugin, capture output in a logfile.
if [ -n "$cxxarch" ]; then
  # Universal binary (OS X): Pure can't do this on its own, so we need to run
  # it twice with the appropriate options for the architecture and use lipo to
  # assemble the final object file. Note that this requires that Pure itself
  # was built as a universal binary so that we can invoke it as a 32 bit
  # program. You'll also need universal binaries for all addon modules used by
  # the compiled script.
  objs=""
  for arch in $cxxarch; do
    if [ "$arch" = "i386" ]; then march="x86"; fi
    if [ "$arch" = "x86_64" ]; then march="x86-64"; fi
    archobjname=`echo $objname|sed -e "s/\.o\$/-$march.o/"`
    # NOTE: The -fPIC option is always needed here, in order to make llc
    # produce a relocatable binary also for x86.
    echo arch -arch $arch pure -fPIC -march=$march -c $filename -o $archobjname --main=$loader
    (arch -arch $arch pure -v0100 -fPIC -march=$march -c $tmpname $filename -o $archobjname --main=$loader 2>&1) | tee $logname
    # check the result, in case anything went wrong during compilation
    rc=$?
    if [ $rc -ne 0 ] ; then
      rm -f $logname $tmpname $objs
      exit $rc
    fi
    objs="$objs $archobjname"
  done
  echo lipo -create $objs -output $objname
  lipo -create $objs -output $objname
  rc=$?
  rm -f $tmpname $objs
  if [ $rc -ne 0 ] ; then
    rm -f $logname
    exit $rc
  fi
else
  echo pure $PIC -c $filename -o $objname --main=$loader
  (pure -v0100 $PIC -c $tmpname $filename -o $objname --main=$loader 2>&1) | tee $logname
  # check the result, in case anything went wrong during compilation
  rc=$?
  rm -f $tmpname
  if [ $rc -ne 0 ] ; then
    rm -f $logname
    exit $rc
  fi
fi

# Grab the libraries we need to link against from the logfile.
extralibs=`tail -1 $logname | sed -e "s/^Link with: .*[.]o//"`
rm -f $logname

# We should have an object file now; if not then something went wrong and we
# bail out with an error message.
if [ ! -f $objname ] ; then
  echo "$0: couldn't create object file $objname" >&2
  exit 1
fi

if [[ $(uname) == Darwin ]]; then
  # Initialize the bundle.
  mkdir -p $output/Contents/MacOS
  printf '%s' 'BNDL????' > $output/Contents/PkgInfo
  sed -e "s?@name@?$plugin?g;s?@version@?1.0.0?g" > $output/Contents/Info.plist <<EOF
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleDevelopmentRegion</key>
	<string>English</string>
	<key>CFBundleExecutable</key>
	<string>@name@</string>
	<key>CFBundleIdentifier</key>
	<string>@name@</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>@name@</string>
	<key>CFBundlePackageType</key>
	<string>BNDL</string>
	<key>CFBundleShortVersionString</key>
	<string>@version@</string>
	<key>CFBundleSignature</key>
	<string>????</string>
	<key>CFBundleVersion</key>
	<string>@version@</string>
	<key>CSResourcesFileMapped</key>
	<true/>
</dict>
</plist>
EOF
fi

# Link with the wrapper module.
echo $CXX $shared -o "$soname" $ARCH $MOD_CFLAGS $INCLUDES -D__cdecl= -DPLUGIN_NAME="\"$plugin\"" -DLOADER_NAME="$loader" $libdir/pure/pureplugin.cc $extrasources $objname $MOD_LDFLAGS $extralibs $LIBS
$CXX $shared -o "$soname" $ARCH $MOD_CFLAGS $INCLUDES -D__cdecl= -DPLUGIN_NAME="\"$plugin\"" -DLOADER_NAME="$loader" $libdir/pure/pureplugin.cc $extrasources $objname $MOD_LDFLAGS $extralibs $LIBS
# check the result, in case anything went wrong during linkage
rc=$?
rm -f $objname
if [ $rc -ne 0 ] ; then
  rm -Rf "$output"
  exit $rc
fi

echo output written to $output
exit 0
